﻿using Core.Log;
using Core.Utility.Extendsions.Json;
using Core.Utility.Extensions;
using Core.Utility.Extensions.Json;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Xml;

namespace Core.Utility.Helper
{
    /// <summary>
    /// JSON助手类
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 转换，通常用于属性、字段相同的两个类、不同JSON输出的场景
        /// </summary>
        /// <typeparam name="TResult">转换结果类型</typeparam>
        /// <typeparam name="TOriginal">转换原始类型</typeparam>
        /// <param name="tr"></param>
        /// <returns></returns>
        public static TResult Converter<TResult, TOriginal>(TOriginal? tr)
            where TResult : class, new()
        {
            return Deserialize<TResult>(Serialize(tr, Newtonsoft.Json.Formatting.Indented,true),true) ?? new TResult();
        }

        /// <summary>
        /// 获取IsoDateTimeConverter的JsonSerializerSettings
        /// DateTimeFormat：yyyy-MM-dd HH:mm:ss
        /// </summary>
        /// <returns></returns>
        public static JsonSerializerSettings IsoDateTimeConverterJsonSerializerSettings()
        {
            IsoDateTimeConverter timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
            var settings = new JsonSerializerSettings()
            {
                Converters = new List<JsonConverter>()
                {
                    timeConverter,
                    new JsonLongParseStringConverter()
                }
            };
            return settings;
        }

        /// <summary>
        /// 获取JObject的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jObject"></param>
        /// <param name="jObjectKey"></param>
        /// <param name="defaultT">参数不存在的默认值</param>
        /// <returns></returns>
        public static T? GetJObjectValue<T>(this JObject jObject, string jObjectKey, T? defaultT = default(T))
        {
            T? res = default(T);
            if (jObject[jObjectKey] != null)
            {
                try
                {
                    var jTarget = jObject[jObjectKey];                    
                    if (jTarget != null)
                    {
                        if (typeof(T) == typeof(string))
                        {
                            res = jTarget.ToString().ChangeType<T>();
                        }
                        else
                        {
                            res = jTarget.ToObject<T>();
                        }
                    }
                    
                }
                catch
                {
                    res = defaultT;
                }
            }
            return res;
        }

        /// <summary>
        /// 获取数组类型JObject的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jObject"></param>
        /// <param name="jObjectKey"></param>
        /// <param name="defaultT"></param>
        /// <returns></returns>
        public static List<T?>? GetJObjectListValue<T>(this JObject jObject, string jObjectKey, List<T?>? defaultT = null)
        {
            List<T?>? res = new List<T?>();
            if (jObject[jObjectKey] != null)
            {
                try
                {
                    var jTarget = jObject[jObjectKey];
                    if (jTarget != null)
                    {
                        res = jTarget.ToObject<List<T?>>();
                    }
                }
                catch
                {
                    try
                    {
                        var jTarget = jObject[jObjectKey];
                        if (jTarget != null)
                        {
                            T? resT = jTarget.ToObject<T?>();
                            res?.Add(resT);
                        }
                    }
                    catch
                    {
                        res = defaultT;
                    }
                }
            }
            else
            {
                res = defaultT;
            }
            return res;
        }

        /// <summary>
        /// 获取JObject的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jToken"></param>
        /// <param name="jObjectKey"></param>
        /// <param name="defaultT">参数不存在的默认值</param>
        /// <returns></returns>
        public static T? GetJTokenValue<T>(this JToken jToken, string jObjectKey, T? defaultT = default(T))
        {
            T? res = default(T);
            var jTokenObject = jToken[jObjectKey];
            if (jTokenObject != null)
            {
                try
                {
                    res = jTokenObject.ToObject<T>();
                }
                catch
                {
                    res = defaultT;
                }
            }
            return res;
        }

        /// <summary>
        /// 获取JObject的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jArray"></param>
        /// <param name="jObjectKey"></param>
        /// <param name="defaultT">参数不存在的默认值</param>
        /// <returns></returns>
        public static T? GetJAarrayValue<T>(this JArray jArray, string jObjectKey, T? defaultT = default(T))
        {
            T? res = default(T);
            var jArrayObject = jArray[jObjectKey];
            if (jArrayObject != null)
            {
                try
                {
                    res = jArrayObject.ToObject<T>();
                }
                catch
                {
                    res = defaultT;
                }
            }
            return res;
        }

        //public static JsonSerializer JsonSerializerCustom()
        //{
        //    JsonSerializer jsonSerializer = new JsonSerializer();
        //    //日期格式化
        //    jsonSerializer.DateFormatHandling = DateFormatHandling.IsoDateFormat;
        //    jsonSerializer.DateFormatString = "yyyy-MM-dd HH:mm:ss";
        //    //空值处理
        //    jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
        //    return jsonSerializer;
        //}

        #region 原生序列化、反序列化
        ///// <summary>
        ///// 序列化JSON
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="t"></param>
        ///// <returns></returns>
        //public static string Serialize<T>(this T t) where T : class
        //{
        //    using (MemoryStream ms = new MemoryStream())
        //    {
        //        string strResult = string.Empty;
        //        try
        //        {
        //            var ser = new DataContractJsonSerializer(t.GetType());
        //            ser.WriteObject(ms, t);
        //            byte[] json = ms.ToArray();
        //            strResult = Encoding.UTF8.GetString(json, 0, json.Length);
        //        }
        //        catch (Exception ex)
        //        {
        //            throw new Exception("序列化JSON失败!\r\n" + ex.Message, ex);
        //        }
        //        finally
        //        {
        //            ms.Close();
        //        }
        //        return strResult;
        //    };
        //}

        ///// <summary>
        ///// 序列化JSON
        ///// </summary>
        ///// <param name="obj"></param>
        ///// <param name="objSourceType"></param>
        ///// <returns></returns>
        //public static string Serialize(this object obj, Type objSourceType)
        //{
        //    using (MemoryStream ms = new MemoryStream())
        //    {
        //        string strResult = string.Empty;
        //        try
        //        {
        //            var ser = new DataContractJsonSerializer(objSourceType);
        //            ser.WriteObject(ms, obj);
        //            byte[] json = ms.ToArray();
        //            strResult = Encoding.UTF8.GetString(json, 0, json.Length);
        //        }
        //        catch (Exception ex)
        //        {
        //            throw new Exception("序列化JSON失败!\r\n" + ex.Message, ex);
        //        }
        //        finally
        //        {
        //            ms.Close();
        //        }
        //        return strResult;
        //    };
        //}

        ///// <summary>
        ///// 反序列化JSON
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="json"></param>
        ///// <returns></returns>
        //public static T Deserialize<T>(this string json) where T : class
        //{
        //    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        //    {
        //        try
        //        {
        //            var ser = new DataContractJsonSerializer(typeof(T));
        //            T result = ser.ReadObject(ms) as T;
        //            ms.Close();

        //            return result;
        //        }
        //        catch (Exception ex)
        //        {
        //            throw new Exception("反序列化JSON失败!\r\n" + ex.Message, ex);
        //        }
        //        finally
        //        {
        //            ms.Close();
        //        }
        //    }
        //}

        ///// <summary>
        ///// 反序列化JSON
        ///// </summary>
        ///// <param name="json"></param>
        ///// <param name="type"></param>
        ///// <returns></returns>
        //public static object Deserialize(this string json, Type type)
        //{
        //    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
        //    {
        //        try
        //        {
        //            var ser = new DataContractJsonSerializer(type);
        //            object result = ser.ReadObject(ms);
        //            ms.Close();

        //            return result;
        //        }
        //        catch (Exception ex)
        //        {
        //            throw new Exception("反序列化JSON失败!\r\n" + ex.Message, ex);
        //        }
        //        finally
        //        {
        //            ms.Close();
        //        }
        //    }
        //}
        #endregion  原生序列化、反序列化

        /// <summary>
        /// JsonConvert的序列化方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="formatting"></param>
        /// <param name="useJsonOriginalPropertyContractResolver">使用JSON原始属性契约解析器</param>
        /// <returns></returns>
        public static string? Serialize<T>(this T? t, Newtonsoft.Json.Formatting formatting = Newtonsoft.Json.Formatting.Indented,bool useJsonOriginalPropertyContractResolver = false)
        {
            IContractResolver? contractResolver = null;
            if (useJsonOriginalPropertyContractResolver)
            {
                contractResolver = new JsonOriginalPropertyContractResolver();
            }
            return SerializeCustomContractResolver(t, formatting, contractResolver);
        }


        /// <summary>
        /// JsonConvert的序列化方法，用于异常输出，如果序列化出现异常，将尝试将 t?.ToString() 返回
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="formatting"></param>
        /// <param name="useJsonOriginalPropertyContractResolver">使用JSON原始属性契约解析器</param>
        /// <returns></returns>

        public static string? EexceptionSerialize<T>(this T? t, Newtonsoft.Json.Formatting formatting = Newtonsoft.Json.Formatting.Indented, bool useJsonOriginalPropertyContractResolver = false)
        {
            string? res = t?.ToString();
            try
            {
                IContractResolver? contractResolver = null;
                if (useJsonOriginalPropertyContractResolver)
                {
                    contractResolver = new JsonOriginalPropertyContractResolver();
                }
                res = SerializeCustomContractResolver(t, formatting, contractResolver);
            }
            catch (Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"尝试将异常参数进行JSON序列化失败;");
                sb.AppendLine($"参数:");
                sb.AppendLine($"\t t.Type => {t?.GetType()}");
                sb.AppendLine($"\t t => {t}");
                AppTrace.Logger.LogError(ex, sb.ToString());
            }
            return res;
        }

        /// <summary>
        /// JsonConvert的序列化方法(压缩JSON字符串)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static string SerializeCompress<T>(this T? t)
        {
            IsoDateTimeConverter timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
            return JsonConvert.SerializeObject(t, Newtonsoft.Json.Formatting.None, new JsonConverter[] { timeConverter, new JsonLongParseStringConverter() });
            //return JsonConvert.SerializeObject(t, Formatting.None).Replace("\r","").Replace("\n","").Replace("\t","");
        }

        /// <summary>
        /// JsonConvert的反序列化方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="json"></param>
        /// <param name="useJsonOriginalPropertyContractResolver">使用JSON原始属性契约解析器，通常用于子、父类互转的场景</param>
        /// <returns></returns>
        public static T Deserialize<T>(this string? json,bool useJsonOriginalPropertyContractResolver = false)
            where T:new()
        {
            IContractResolver? contractResolver = null;
            if (useJsonOriginalPropertyContractResolver)
            {
                contractResolver = new JsonOriginalPropertyContractResolver();
            }
            return DeserializeCustomContractResolver<T>(json, contractResolver) ?? new T();
        }

        /// <summary>
        /// JsonConvert的匿名类型反序列化方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="json"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T DeserializeAnonymousType<T>(this string json, T t)
            where T : class, new()
        {
            JsonSerializerSettings settings = IsoDateTimeConverterJsonSerializerSettings();
            return JsonConvert.DeserializeAnonymousType(json, t, settings) ?? new T();
        }

        /// <summary>
        /// Json字符串格式化
        /// </summary>
        /// <param name="josn"></param>
        /// <returns></returns>
        public static string? JsonStringFormat(this string? josn)
        {
            try
            {
                if (!string.IsNullOrEmpty(josn))
                {
                    var jsonObj = Deserialize<object>(josn);
                    josn = Serialize<object>(jsonObj);
                }
            }
            catch
            {
            }
            return josn;
        }

        /// <summary>
        /// Json字符串转XML
        /// </summary>
        /// <param name="json"></param>
        /// <param name="rootName"></param>
        /// <returns></returns>
        public static string? ToXml(this string? json, string? rootName = "")
        {
            try
            {
                string jsonStr = json.GetValueOrDefault();
                return JsonConvert.DeserializeXmlNode(jsonStr, rootName)?.OuterXml;
            }
            catch (Exception ex)
            {
                throw new Exception($"Json转XML出错：\r\n{ex.Message}");
            }
        }

        /// <summary>
        /// Xml转JSON对象
        /// </summary>
        /// <param name="xmlNode"></param>
        /// <param name="omitRootObject"></param>
        /// <returns></returns>
        public static JObject XmlToJsonObject(this XmlNode? xmlNode, bool omitRootObject = true)
        {
            try
            {
                string jsonString = XmlToJosnString(xmlNode, omitRootObject);
                JObject jObject = JObject.Parse(jsonString);
                return jObject;
            }
            catch (Exception ex)
            {
                throw new Exception($"XML转JSON对象出错:\r\n{ex.Message}", ex);
            }
        }

        /// <summary>
        /// Xml字符串转JSON对象
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="omitRootObject"></param>
        /// <returns></returns>
        public static JObject XmlToJsonObject(this string? xml, bool omitRootObject = true)
        {
            try
            {
                string jsonString = XmlToJosnString(xml, omitRootObject);
                JObject jObject = JObject.Parse(jsonString);
                return jObject;
            }
            catch (Exception ex)
            {
                throw new Exception($"XML字符串转JSON对象出错:\r\n{ex.Message}", ex);
            }
        }

        /// <summary>
        /// Xml转为Json字符串
        /// </summary>
        /// <param name="xmlNode">要序列化的节点</param>
        /// <param name="omitRootObject">省略写入根对象</param>
        /// <returns></returns>
        public static string XmlToJosnString(this XmlNode? xmlNode, bool omitRootObject = true)
        {
            try
            {
                IsoDateTimeConverter timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
                return JsonConvert.SerializeXmlNode(xmlNode, Newtonsoft.Json.Formatting.Indented, omitRootObject);
            }
            catch (Exception ex)
            {
                throw new Exception($"XML转Json字符串出错：\r\n{ex.Message}", ex);
            }
        }

        /// <summary>
        /// Xml反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xml">xml文本</param>
        /// <param name="omitRootObject">是否忽略根节点</param>
        /// <returns></returns>
        public static T XmlDeserialize<T>(this string? xml, bool omitRootObject = true) where T : new()
        {
            try
            {
                string jsonString = XmlToJosnString(xml, omitRootObject);
                var v = Deserialize<T>(jsonString);
                T res = Deserialize<T>(jsonString) ?? new();
                return res;
            }
            catch (Exception ex)
            {
                throw new Exception($"反序列化XML出错:\r\n{ex.Message}");
            }
        }

        /// <summary>
        /// Xml转为Json字符串
        /// </summary>
        /// <param name="xml">xml节点字符串</param>
        /// <param name="omitRootObject">省略写入根对象</param>
        /// <returns></returns>
        public static string XmlToJosnString(this string? xml, bool omitRootObject = true)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xml.GetValueOrDefault());
                if (xml?.Contains(@"<?xml") == true)
                {
                    string? loadXml = doc.DocumentElement?.OuterXml;
                    doc.LoadXml(loadXml.GetValueOrDefault());
                }
                IsoDateTimeConverter timeConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" };
                return JsonConvert.SerializeXmlNode(doc, Newtonsoft.Json.Formatting.Indented, omitRootObject);
            }
            catch (Exception ex)
            {
                throw new Exception($"XML字符串转Json字符串出错：\r\n{ex.Message}", ex);
            }
        }

        /// <summary>
        /// 泛型对象转Xml
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="paramObject"></param>
        /// <param name="rootName"></param>
        /// <returns></returns>
        public static string? ToXml<T>(this T? paramObject, string rootName = "")
        {
            try
            {
                string json = Serialize(paramObject).GetValueOrDefault();
                return JsonConvert.DeserializeXmlNode(json, rootName)?.OuterXml;
            }
            catch (Exception ex)
            {
                throw new Exception($"Json转XML出错：\r\n{ex.Message}");
            }
        }

        /// <summary>
        /// JsonConvert的序列化方法（将对象转为String，转化失败返回""）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="formatting"></param>
        /// <param name="isOriginalPropertyName">是否使用原始属性名进行序列化</param>
        /// <returns></returns>
        public static string? SerializeToString<T>(T? t, Newtonsoft.Json.Formatting formatting = Newtonsoft.Json.Formatting.Indented, bool isOriginalPropertyName = false)
        {
            try
            {
                IContractResolver? contractResolver = null;
                if (isOriginalPropertyName)
                {
                    contractResolver = new JsonOriginalPropertyContractResolver();
                }
                return SerializeCustomContractResolver(t, formatting, contractResolver);
            }
            catch
            {
                if(t?.GetType() == typeof(string))
                {
                    return t?.ToString();
                }
            }
            return "";
        }

        /// <summary>
        /// JsonConvert的序列化方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="formatting"></param>
        /// <param name="contractResolver">JSON 协定解析器</param>
        /// <param name="useJsonCustomPropertyContractResolver">使用JSON自定义属性契约解析器，当contractResolver=null时，此参数起效</param>
        /// <returns></returns>
        public static string? SerializeCustomContractResolver<T>(T? t, Newtonsoft.Json.Formatting formatting = Newtonsoft.Json.Formatting.Indented, IContractResolver? contractResolver = null,bool useJsonCustomPropertyContractResolver = false)
        {
            var settings = IsoDateTimeConverterJsonSerializerSettings();
            if (contractResolver != null)
            {
                settings.ContractResolver = contractResolver;
            }
            else if (useJsonCustomPropertyContractResolver)
            {
                settings.ContractResolver = new JsonCustomPropertyContractResolver();
            }
            return JsonConvert.SerializeObject(t, formatting, settings);
        }

        /// <summary>
        /// JsonConvert的反序列化方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="json"></param>
        /// <param name="contractResolver">JSON 协定解析器</param>
        /// <param name="useJsonCustomPropertyContractResolver">使用JSON自定义属性契约解析器，当contractResolver=null时，此参数起效</param>
        /// <returns></returns>
        public static T? DeserializeCustomContractResolver<T>(string? json, IContractResolver? contractResolver = null, bool useJsonCustomPropertyContractResolver = false)
        {
            var settings = IsoDateTimeConverterJsonSerializerSettings();
            if (contractResolver != null)
            {
                settings.ContractResolver = contractResolver;
            }
            else if(useJsonCustomPropertyContractResolver)
            {
                settings.ContractResolver = new JsonCustomPropertyContractResolver();
            }
            string strJson = json ?? "";
            return JsonConvert.DeserializeObject<T>(strJson, settings);
        }

        /// <summary>
        /// 是否为JSON字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsValidJson(this string input)
        {
            if (string.IsNullOrWhiteSpace(input)) { return false; }
            input = input.Trim();
            if ((input.StartsWith("{") && input.EndsWith("}")) || //For object
                (input.StartsWith("[") && input.EndsWith("]"))) //For array
            {
                try
                {
                    var obj = JToken.Parse(input);
                    return true;
                }
                catch (JsonReaderException jex)
                {
                    //Exception in parsing json
                    //Console.WriteLine(jex.Message);
                    return false;
                }
                catch (Exception ex) //some other exception
                {
                    //Console.WriteLine(ex.ToString());
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
    }


}
